Skip to content

fix(integrations): escape Rich markup in --integration-options error messages#3458

Merged
mnriem merged 3 commits into
github:mainfrom
Quratulain-bilal:fix/integration-options-shlex
Jul 22, 2026
Merged

fix(integrations): escape Rich markup in --integration-options error messages#3458
mnriem merged 3 commits into
github:mainfrom
Quratulain-bilal:fix/integration-options-shlex

Conversation

@Quratulain-bilal

@Quratulain-bilal Quratulain-bilal commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Follow-up hardening to #3457 (the unbalanced-quote crash, since fixed on main).

_parse_integration_options interpolated user-controlled option tokens straight into console.print in two branches:

  • the unexpected value branch — a token that does not start with -;
  • the unknown option branch — a token that starts with - but is not declared.

Because console.print parses Rich markup, a token carrying an unbalanced tag (e.g. [/red]foo or --[/red]bad) raises rich.errors.MarkupError and leaks a traceback instead of the clean typer.Exit(1) every other bad-input path produces.

fix: wrap both token values in rich.markup.escape(...) before printing, so malformed markup is shown literally and the command still exits 1.

scope note: the shlex.split ValueError conversion for #3457 is already on main; this PR does not re-introduce it. The only production change here is the markup escaping of the two token prints.

Added test_bad_option_token_with_rich_markup_exits_cleanly, which asserts a clean typer.Exit for both the unexpected-value ([/red]foo) and unknown-option (--[/red]bad) branches; it fails on the pre-escape code (raw MarkupError) and passes with the fix. The existing test_unbalanced_quote_exits_cleanly continues to cover the shlex path.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Handles malformed integration-option quoting without exposing ValueError tracebacks.

Changes:

  • Converts shlex.split failures into typer.Exit(1).
  • Adds regression coverage for unbalanced quotes.
Show a summary per file
File Description
src/specify_cli/integrations/_helpers.py Handles malformed quoting during option parsing.
tests/integrations/test_integration_subcommand.py Tests clean failure on unbalanced quotes.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Medium

Comment thread src/specify_cli/integrations/_helpers.py Outdated

@mnriem mnriem left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please address Copilot feedback

@Quratulain-bilal

Quratulain-bilal commented Jul 13, 2026

Copy link
Copy Markdown
Contributor Author

escaped the value before interpolating it in aa810ba — you're right that --commands-dir "[/red]foo tripped the intended ValueError but then the error print itself raised MarkupError on the unbalanced tag and leaked a traceback anyway.

swept the two sibling branches in the same function too (the 'unexpected option value' and 'unknown option' prints both interpolate the raw token), since a bare [/red]foo token would hit the same wall without an unbalanced quote.

regression covers both: an unbalanced-quote value carrying markup, and a plain markup token. confirmed both raise MarkupError on the pre-fix code and exit cleanly with the escape.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

  • Files reviewed: 2/2 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

@mnriem

mnriem commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Please resolve conflicts

…oting

_parse_integration_options called shlex.split(raw_options) unguarded. an
unbalanced quote (e.g. --integration-options='--commands-dir "foo') makes
shlex raise ValueError('No closing quotation'), so a raw traceback escaped
instead of the typer.Exit(1) error every other bad-input path in this function
produces. reachable from specify init and every integration install/switch/
upgrade/migrate that accepts --integration-options.

wrap the split and convert ValueError into the same clean CLI error. added a
regression test; confirmed it fails on the pre-fix code (raw ValueError).
the malformed-quoting handler (and the unexpected/unknown option
branches) interpolate raw_options/token into console.print. a value
carrying an unbalanced rich tag like '--commands-dir "[/red]foo' first
trips the intended shlex ValueError, but the error print then raises
rich.errors.MarkupError and leaks a traceback anyway. escape all three
before printing so the clean typer.Exit survives.

added a regression covering both the shlex path and a bare markup token.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

  • Files reviewed: 2/2 changed files
  • Comments generated: 2
  • Review effort level: Medium

Comment thread src/specify_cli/integrations/_helpers.py
Comment thread tests/integrations/test_integration_subcommand.py Outdated
@mnriem

mnriem commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Please address Copilot feedback

The removed test's docstring claimed the shlex failure branch
interpolates raw_options into console.print; it only prints {exc},
which never contains the caller's markup. Its two assertions also
duplicated test_bad_option_token_with_rich_markup_exits_cleanly (the
'[/red]foo' case) and the shlex-path case already covered by
test_unbalanced_quote_exits_cleanly. The real change here remains the
escape() of the two user-controlled token prints.
@Quratulain-bilal

Copy link
Copy Markdown
Contributor Author

Addressed the Copilot feedback. The flagged test (test_malformed_quoting_with_rich_markup_exits_cleanly) had an inaccurate docstring — the shlex failure branch prints only {exc}, which never carries the caller's markup, so that path was already clean via the existing test_unbalanced_quote_exits_cleanly. Its [/red]foo assertion also duplicated test_bad_option_token_with_rich_markup_exits_cleanly. Removed the redundant test; the substantive change remains escaping the two user-controlled token prints (the unexpected-value and unknown-option branches) so an unbalanced Rich tag exits cleanly instead of raising MarkupError.

@Quratulain-bilal Quratulain-bilal changed the title fix(integrations): exit cleanly on malformed --integration-options quoting fix(integrations): escape Rich markup in --integration-options error messages Jul 21, 2026
@Quratulain-bilal

Copy link
Copy Markdown
Contributor Author

Updated the PR title and description to match the actual scope. You're right that the shlex.split ValueError conversion for #3457 is already on main and unchanged in this diff — the only production behavior here is escaping the two user-controlled token prints (unexpected-value and unknown-option branches) so an unbalanced Rich tag exits cleanly instead of raising MarkupError. The title now says "escape Rich markup in --integration-options error messages" and the body frames this as follow-up hardening to the already-fixed #3457 rather than re-adding that fix.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

  • Files reviewed: 2/2 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

@mnriem
mnriem self-requested a review July 22, 2026 11:49
@mnriem
mnriem merged commit d9e4565 into github:main Jul 22, 2026
12 checks passed
@mnriem

mnriem commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants